package com.tvunetworks.center.user.controller;

import com.tvunetworks.center.user.config.redis.RedisConfig;
import com.tvunetworks.center.user.model.pojo.RedisTemplateAggregator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program:
 * @description:
 * @author HenryChen
 * @create: 7/20/2019 2:10 PM
 **/

@RestController
@RequestMapping("/redis")
@Slf4j
public class RedisController {


    private static Map<String, RedisTemplateAggregator> REDISTEMPLATEMAP = new ConcurrentHashMap<>();

    // default
    @Autowired
    private RedisTemplate redisTemplate;

    // default
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     *
     * @param key key
     * @param type type
     * @param redisProperties redisProperties
     * @return Map<
     */
    @GetMapping("get")
    @ResponseBody
    public Map<String,Object> get(String key, String type,RedisProperties redisProperties) {
//        NONE("none"), STRING("string"), LIST("list"), SET("set"), ZSET("zset"), HASH("hash");

        // The result of the key in redis
        Object result = null;

        RedisTemplateAggregator targetRedisTempplateAggregator;

        RedisTemplate targetTempRedisTemplate;

        // localhost 说明对方没有传 host 参数,直接使用当前项目的 redisTemplate 对象
        // 否则就实例化对应的 restTemplate
        if(StringUtils.equals("localhost",redisProperties.getHost())){
            targetRedisTempplateAggregator = getDefaultRedisTemplateAggregator();
        } else {
            targetRedisTempplateAggregator =
                    REDISTEMPLATEMAP.get(redisProperties.getHost()+"_"+redisProperties.getPort());

            if(targetRedisTempplateAggregator == null){
                targetRedisTempplateAggregator = initRedisTemplateAggregator(redisProperties);
            }
        }


        if ("string".equals(type)) {
            targetTempRedisTemplate = targetRedisTempplateAggregator.getStringRedisTemplate();
        } else {
            targetTempRedisTemplate = targetRedisTempplateAggregator.getRedisTemplate();
        }

        DataType keyType = targetTempRedisTemplate.type(key);
        Map<String, Object> resultMap = new HashMap<>();

        if (DataType.STRING.equals(keyType)) {
            result = targetTempRedisTemplate.opsForValue().get(key);
        } else if (DataType.LIST.equals(keyType)) {
            result = targetTempRedisTemplate.opsForList().range(key, 0, -1);
        } else if (DataType.HASH.equals(keyType)) {
            result = targetTempRedisTemplate.opsForHash().entries(key);
        } else if (DataType.ZSET.equals(keyType)) {
            result = targetTempRedisTemplate.opsForZSet().range(key, 0, -1);
        } else if (DataType.SET.equals(keyType)) {
            result = targetTempRedisTemplate.opsForSet().members(key);
        } else if (DataType.NONE.equals(keyType)) {
            resultMap.put("keyType", keyType);
            resultMap.put("result", "Key not exist");
            return resultMap;
        }

        resultMap.put("keyType", keyType);
        resultMap.put("result", result);

        return resultMap;
    }

    /**
     *
     * @return return
     */
    @GetMapping("serverList")
    @ResponseBody
    public Set<String> serverList(){

        Set<String> redisIpPort = REDISTEMPLATEMAP.keySet();

        return redisIpPort;

    }

    /**
     *
     * @return String
     */
    @GetMapping("reset")
    @ResponseBody
    public String reset(){
        REDISTEMPLATEMAP.clear();
        return "success";
    }



    /**
     *
     * 初始化一个新的 {@link RedisTemplateAggregator}
     * 并放入 {@link RedisController#REDISTEMPLATEMAP} 中
     *
     * @param redisProperties redisProperties
     * @return 初始化的 {@link RedisTemplateAggregator}
     */
    public RedisTemplateAggregator initRedisTemplateAggregator(RedisProperties redisProperties) {
        RedisStandaloneConfiguration redisStandaloneConfiguration
                = new RedisStandaloneConfiguration(redisProperties.getHost(), redisProperties.getPort());

        // init redisConnectionFactory
        LettuceConnectionFactory redisConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
        redisConnectionFactory.afterPropertiesSet(); // Establish redis client

        RedisConfig redisConfig = new RedisConfig();
        // init RedisTemplate and StringRedisTemplate
        RedisTemplate<Object, Object> redisTemplate = redisConfig.redisTemplate(redisConnectionFactory);
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(redisConnectionFactory);

        // set
        RedisTemplateAggregator redisTemplateAggregator = new RedisTemplateAggregator();
        redisTemplateAggregator.setRedisTemplate(redisTemplate)
                .setStringRedisTemplate(stringRedisTemplate);

        REDISTEMPLATEMAP.put(redisProperties.getHost() + "_" + redisProperties.getPort(), redisTemplateAggregator);

        log.info("Init new redis template, Host: [{}] , Port: [{}]",redisProperties.getHost(),redisProperties.getPort());

        return redisTemplateAggregator;
    }


    @PostConstruct
    private RedisTemplateAggregator getDefaultRedisTemplateAggregator(){

        RedisTemplateAggregator defaultRedisTemplateAggregator = REDISTEMPLATEMAP.get("default");

        if(defaultRedisTemplateAggregator == null){
            defaultRedisTemplateAggregator = new RedisTemplateAggregator();
            defaultRedisTemplateAggregator.setRedisTemplate(redisTemplate)
                    .setStringRedisTemplate(stringRedisTemplate);
            REDISTEMPLATEMAP.put("default",defaultRedisTemplateAggregator);
        }
        return defaultRedisTemplateAggregator;
    }

}
